/*
    This source file is part of GeNa project.
    Copyright © GeNa project 2008
    For the latest info, see http://code.google.com/p/genaproject/ or  http://lumpyproject.forums-rpg.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>. */

#include <action.h>

void Action::saveObject(Object* obj)
{
    //If it is a new Object, just update the copy
    listOfObject::iterator iter = std::find_if( newObjectsCopy.begin(), newObjectsCopy.end(), bind( &Object::getId, _1) == obj->getId());
    if( iter != newObjectsCopy.end())
    {

        Object::getObject((*iter)->getId())->copyTo(*iter);
        (*iter)->toId();
        return;
    }

    //If it is a previously modified object, keep the original
    if(std::count_if( modifiedObjectsCopy.begin(), modifiedObjectsCopy.end(), bind( &Object::getId, _1) == obj->getId()))
        return;

    //Else add it
    Object* copy = obj->copy();
    copy->toId();
    modifiedObjectsCopy.push_back(copy);
}


void Action::removeObject(Object* obj)
{
    //If obj was a new object, just remove it from new objects list and delete it.
    listOfObject::iterator iter = std::find_if( newObjectsCopy.begin(), newObjectsCopy.end(), bind( &Object::getId, _1) == obj->getId());
    if( iter != newObjectsCopy.end())
    {
        obj->unlink();
        delete obj;

        delete *iter;
        newObjectsCopy.erase(iter);

        return;
    }

    //Add obj to removed objects list and remove it from modified objects list if it was modified previously.
    obj->unlink();
    obj->toId();
    removedObjectList.push_back(obj);

    iter = std::find_if( modifiedObjectsCopy.begin(), modifiedObjectsCopy.end(), bind( &Object::getId, _1) == obj->getId());
    if( iter != modifiedObjectsCopy.end())
    {
        delete *iter;
        modifiedObjectsCopy.erase(iter);
    }
}

void Action::saveAllNewObjects()
{
    for( listOfObject::iterator iter = newObjectsCopy.begin(); iter != newObjectsCopy.end(); iter++)
    {
        Object::getObject((*iter)->getId())->copyTo(*iter);
        (*iter)->toId();
    }
}

void Action::addAction(boost::function0<void> action)
{
    actionList.push_back(action);
}

void Action::addUndoRedoPair(boost::function0<void> undo, boost::function0<void> redo)
{
    actionList.push_back( UndoRedo(undo, redo));
}

void Action::restoreObjectsState()
{

    std::for_each( modifiedObjectsCopy.begin(), modifiedObjectsCopy.end(), (bind(&Object::fromId,_1), _1 = bind(&Object::swap,_1), bind(&Object::toId, _1))); //Swap object


    Object* obj;
    var_type<Object*>::type vobj(var(obj));
    std::for_each( removedObjectList.begin(), removedObjectList.end(), (vobj = bind( &Object::copy, _1), bind(&Object::link, vobj), bind(&Object::fromId,vobj))); //Add removed object
    std::for_each( newObjectsCopy.begin(), newObjectsCopy.end(), (  vobj = bind(&Object::getObject,bind(&Object::getId,_1)), //Removed new object
                                                                    bind(&Object::unlink,vobj),
                                                                    bind(delete_ptr(), vobj)));


    if(isUndo)
        std::for_each( actionList.begin(), actionList.end(), bind(_1)); //Call each function
    else
        std::for_each( actionList.rbegin(), actionList.rend(), bind(_1)); //Call each function

    std::swap(newObjectsCopy, removedObjectList);
}
